////////////////////////////////////////////////////////////////////////////////
// reflection_lighting.fx
// This shader provides per pixel lighting and a clipping plane. Used for water 
// reflection and refraction since meshes under/over sea level need to be clipped
////////////////////////////////////////////////////////////////////////////////

/////////////
// GLOBALS //
/////////////
matrix World;
matrix View;
matrix Projection;

float3 CameraPosition;
float4 DefaultColor;

Texture2D txDiffuse;
Texture2D txNormal;

bool  EnableLighting = true; 
bool  EnableTexture = true;
bool  EnableBumpMapping = true;

float4 ClipPlane;

//////////////
// STRUCTS //
//////////////
struct Material
{
    float4 Ks;
    float4 Ka;
    float4 Kd;
    float4 Ke;
    float Shininess;
};

struct Light
{
    float4 Position;
    float4 Color;
    float4 Ambient;
    float3 Attenuation;
};

Light    g_lights[2];

Material g_material;

///////////////////
// SAMPLE STATES //
///////////////////
SamplerState samLinear
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};

//////////////////////////
// DEPTH-STENCIL STATES //
//////////////////////////
DepthStencilState EnableDepth{
	DepthEnable = true; 
	DepthWriteMask = ALL;
	DepthFunc = Less;
	StencilEnable = false; 
};

//////////////
// TYPEDEFS //
//////////////
struct VS_INPUT
{
    float4 pos          : POSITION;        
    float3 norm         : NORMAL;          
    float3 tan          : TANGENT;  
    float3 binorm       : BINORMAL;  
    float2 tex          : TEXCOORD;	
};

struct VS_OUTPUT
{
    float4 pos : SV_POSITION;
    float2 tex : TEXCOORD0;    
    float3 view: TEXCOORD1;
    float3 light0: TEXCOORD2;
    float3 light1: TEXCOORD3;
    float3 normal: TEXCOORD4;
	float clip : SV_ClipDistance0;
};

//--------------------------------------------------------------------------------------
// Vertex Shader - Phong shading: illuminazione per pixel
//--------------------------------------------------------------------------------------
VS_OUTPUT VS( VS_INPUT input )
{
    VS_OUTPUT output = (VS_OUTPUT)0;  
    
    float4 worldPos = mul( input.pos, World );
    output.pos = mul( worldPos, View );
    output.pos = mul( output.pos, Projection );

	output.tex = input.tex;

  	output.light0.xyz = (g_lights[0].Position.xyz - worldPos.xyz );   	
  	output.light1.xyz = (g_lights[1].Position.xyz - worldPos.xyz );   	

	output.view = (CameraPosition.xyz - worldPos.xyz);
	
	float3x3 toWorldSpace = float3x3(
	input.tan.x, input.binorm.x, input.norm.x,
	input.tan.y, input.binorm.y, input.norm.y,
	input.tan.z, input.binorm.z, input.norm.z
	);

	float3x3 toTangentSpace = transpose(toWorldSpace);

	output.light0 = mul(toTangentSpace, output.light0);
	output.light1 = mul(toTangentSpace, output.light1);
	output.view = mul(toTangentSpace, output.view);
    output.normal = mul(toTangentSpace, output.normal);

	//Set the clipping plane. Clip everything under water plane for reflection. Above water plane for refraction.
	output.clip = dot(mul(input.pos, World), ClipPlane);

	return output;
}

//--------------------------------------------------------------------------------------
// Pixel Shader - Phong shading: per pixel lighting
//--------------------------------------------------------------------------------------
float4 PS( VS_OUTPUT input ) : SV_Target
{
	input.normal = normalize(input.normal);
	input.view = normalize(input.view);
	input.light0 = normalize(input.light0);
	input.light1 = normalize(input.light1);
  	
	float4 color = txDiffuse.Sample(samLinear, input.tex);
	float3 normal;
  	if(EnableBumpMapping)
	{
	normal = 2 * (txNormal.Sample(samLinear, input.tex) - 0.5);
	}
  	else
  		normal = input.normal;
    
    if(EnableLighting){
		
		float4 output; 
		output.rgba = 0;

        float3 halfAngle0 = normalize( (input.view + input.light0) / 2 );
        float3 halfAngle1 = normalize( (input.view + input.light1) / 2 );
     
	    if(!EnableTexture){
			color = g_material.Kd;
		}
        output += max(0,dot( input.light0, normal ) * g_lights[0].Color * color ) ;
        output += max(0,dot( input.light1, normal ) * g_lights[1].Color * color ) ;
        
	    if(!EnableTexture){
			color = g_material.Ka;
		}
		output += g_lights[0].Ambient * color;
		output += g_lights[1].Ambient * color;

        output += max(0,pow( dot( halfAngle0, normal ), g_material.Shininess ) * g_lights[0].Color * g_material.Ks );
        output += max(0,pow( dot( halfAngle1, normal ), g_material.Shininess ) * g_lights[1].Color * g_material.Ks );

	    output += g_material.Ke;
  
		return output;
    }
    else{
		color = DefaultColor;
    }        
		
	return color; 
}

//--------------------------------------------------------------------------------------
technique10 ReflectionWithLighting
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_4_0, VS() ) );
        SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_4_0, PS() ) );  
        SetDepthStencilState(EnableDepth,0);
    }
}
